package com.myk.game.gobangchess.rooms;


import com.myk.game.gobangchess.constants.BoardStyleData;
import com.myk.game.gobangchess.CustomBottom;
import com.myk.game.gobangchess.Room;
import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.signs.AroundSign;
import com.myk.game.gobangchess.signs.BadgeSign;
import com.myk.game.gobangchess.signs.ColorSign;
import com.myk.game.gobangchess.signs.LineSign;

import java.util.ArrayList;
import java.util.List;

/**
 * 反五子棋房间
 */
public class AntiGoBangRoom extends Room {

    private boolean isPushState = false; //当前是否推棋状态
    private int pushFromRow, pushFromCol; //推子前所在的位置

    //刚开时出现，落子后消失，点击后能够再点
    CustomBottom cb_balance = new CustomBottom(this, "平衡开局", (player) -> {
        curGrids = getNiJieStyle();
        noticeBlackMove();
        preHistory(); //准备记录日志
    });

    public AntiGoBangRoom(String roomName) {
        super(roomName, "日出和夏日发明的新棋\n\t\t\t\t连五就输？五子不行！通过推子迫使对方连五为负的棋！","反五子棋", BoardStyleData.getGoBangStyle(15,15), true, true);
    }

    private int[][] getNiJieStyle() {
        class PrePoint {
            public int col;
            public int row;
            public int value;

            public PrePoint(int col, int row, int value) {
                this.col = col;
                this.row = row;
                this.value = value;
            }
        }
        PrePoint[][] prePointsGroup = new PrePoint[][]{
                new PrePoint[]{
                        new PrePoint(7, 0, 1),
                        new PrePoint(7, 6, 2),
                        new PrePoint(7, 8, 2),
                        new PrePoint(7, 14, 1),
                },
                new PrePoint[]{
                        new PrePoint(6, 11, 2),
                        new PrePoint(8, 11, 2),
                        new PrePoint(6, 14, 1),
                        new PrePoint(8, 14, 1),
                },
                new PrePoint[]{
                        new PrePoint(13, 1, 1),
                        new PrePoint(8, 6, 2),
                        new PrePoint(6, 8, 2),
                        new PrePoint(2, 12, 1),
                },
                new PrePoint[]{
                        new PrePoint(0, 7, 1),
                        new PrePoint(0, 11, 1),
                        new PrePoint(2, 9, 2),
                        new PrePoint(5, 9, 2),
                },
                new PrePoint[]{
                        new PrePoint(14, 0, 1),
                        new PrePoint(9, 6, 2),
                        new PrePoint(7, 7, 2),
                        new PrePoint(6, 14, 1),
                },
                new PrePoint[]{
                        new PrePoint(11, 2, 1),
                        new PrePoint(6, 7, 2),
                        new PrePoint(8, 7, 2),
                        new PrePoint(3, 12, 1),
                },
                new PrePoint[]{
                        new PrePoint(7, 7, 1),
                        new PrePoint(4, 9, 2),
                        new PrePoint(5, 10, 2),
                        new PrePoint(0, 14, 1),
                },
                new PrePoint[]{
                        new PrePoint(7, 7, 2),
                        new PrePoint(8, 8, 2),
                        new PrePoint(1, 11, 1),
                        new PrePoint(3, 12, 1),
                },
                new PrePoint[]{
                        new PrePoint(6, 7, 2),
                        new PrePoint(8, 7, 2),
                        new PrePoint(5, 10, 1),
                        new PrePoint(9, 10, 1),
                },
                new PrePoint[]{
                        new PrePoint(10, 6, 1),
                        new PrePoint(7, 9, 2),
                        new PrePoint(8, 9, 2),
                        new PrePoint(5, 12, 1),
                },
                new PrePoint[]{
                        new PrePoint(8, 0, 1),
                        new PrePoint(6, 6, 2),
                        new PrePoint(7, 7, 2),
                        new PrePoint(7, 11, 1),
                }
        };
        int[][] style = {
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
        };
        int rdm = (int) (Math.random() * prePointsGroup.length); //随便取一个预设组
        PrePoint[] choosePrePoints = prePointsGroup[rdm];
        for (PrePoint choosePrePoint : choosePrePoints) {
            style[choosePrePoint.row][choosePrePoint.col] = choosePrePoint.value;
        }
        return style;
    }

    @Override
    public String getRuleText() {
        return "黑白双方轮流行动；\n" +
                "选择A：落子到空格\n" +
                "选择B：落子占据对方棋子的位置，然后将对方棋子沿直线/斜线推走到空格\n" +
                "落败条件：形成五子一线\n" +
                "和棋条件：无棋可走";
    }

    @Override
    protected void doStart() {
        super.doStart();
        addCustoms();
    }

    @Override
    public void resetGrids() {
        super.resetGrids();
        isPushState = false;
    }

    private void addCustoms() {
        if (player_black != null) {
            player_black.registerCustomBottom(cb_balance);
        }
        if (player_white != null) {
            player_white.registerCustomBottom(cb_balance);
        }
    }

    private void clearCustoms() {
        if (player_black != null) {
            if (player_black.getCustomBottomList(this).size() > 0) {
                player_black.clearCustomBottom();
                player_black.dispatchCustomBottom();
            }
        }
        if (player_white != null) {
            if (player_white.getCustomBottomList(this).size() > 0) {
                player_white.clearCustomBottom();
                player_white.dispatchCustomBottom();
            }
        }
    }

    public void addNewPutSignal(int newRow, int newCol) {
        signList.add(new AroundSign(getIndex(newRow, newCol), "#00000000", "#6600FF00", 1.2f));
    }

    public void addWaitSignal(int waitRow, int waitCol, int value) {
        String color = value == 1 ? ColorCost.DETAINED_BADGE_BLACK : ColorCost.DETAINED_BADGE_WHITE;
        signList.add(new BadgeSign(getIndex(waitRow, waitCol), "p", 2, color, color));
        List<int[]> cantPutPosList = getCanPushPosList(); //获取禁着点集合
        if (cantPutPosList.size() > 0) {
            List<Integer> ids = new ArrayList<>();
            for (int[] canMovedPos : cantPutPosList) {
                ids.add(getIndex(canMovedPos[0], canMovedPos[1]));
            }
            signList.add(new ColorSign(ids, "#6666CC66")); //浅绿色
        }
    }

    public void addArrowSignal(int startRow, int startCol, int endRow, int endCol) {
        signList.add(new LineSign(getIndex(startRow, startCol), getIndex(endRow, endCol), ColorCost.MOVE_ARROW, 1));
    }

    private List<int[]> getCanPushPosList() {
        List<int[]> canMovedPosList = new ArrayList<>();
        int h = curGrids.length;
        int w = curGrids[0].length;
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                if (isOnTheRay(pushFromRow, pushFromCol, i, j)) {
                    canMovedPosList.add(new int[]{i, j});
                }
            }
        }
        return canMovedPosList;
    }


    @Override
    public void doRule(int row, int col, int value) {
        signList.clear();
        clearCustoms();
        if (value == 1) { //黑方落子判断
            if (isPushState) { //当前是推子状态
                if (isOnTheRay(pushFromRow, pushFromCol, row, col)) { //只能落在原位置的射线上，（射线为直斜8个方向，且不穿过其它棋子）
                    curGrids[pushFromRow][pushFromCol] = 1; //己方黑棋最新落下的位置
                    curGrids[row][col] = 2; //挤走对方白棋的位置
                    isPushState = false; //落完就还原状态
                    addArrowSignal(pushFromRow, pushFromCol, row, col);
                    stepAdd();;
                    if (checkFormation(2)>0) { //此时可以判断白棋是否被黑方形成5连
                        doOver(WinMode.BLACK_WIN,player_black.getNickNameOrTemp() + "执黑棋战胜" + player_white.getNickNameOrTemp());
                    }
                    else {
                        noticeWhiteMove(); //再给白棋走
                    }
                }
            }
            else { //常规落子状态
                if (curGrids[row][col] == 0) { //常规落在空格
                    curGrids[row][col] = 1;
                    addNewPutSignal(row, col);
                    stepAdd();
                    if (checkFormation(1)>0) { //判断成5的为输啊
                        doOver(WinMode.WHITE_WIN,player_white.getNickNameOrTemp() + "执白棋战胜" + player_black.getNickNameOrTemp());
                    }
                    else {
                        noticeWhiteMove();
                    }
                }
                else if (curGrids[row][col] == 2) { //落在对方白子上
                    if (isCantFall(row,col)) return;
                    curGrids[row][col] = 1; //白棋位置被替换
                    stepAdd();
                    if (checkFormation(1)>0) { //此时先判断输赢
                        doOver(WinMode.WHITE_WIN,player_white.getNickNameOrTemp() + "执白棋战胜" + player_black.getNickNameOrTemp());
                    }
                    else { //黑棋进入推棋状态
                        isPushState = true;
                        pushFromRow = row;
                        pushFromCol = col;
                        addWaitSignal(row, col, 1);
                        noticeBlackMove();//通知还是黑棋走
                    }
                }
            }
        }
        else if (value == 2) { //白方落子判断
            if (isPushState) { //当前是推子状态
                if (isOnTheRay(pushFromRow, pushFromCol, row, col)) { //只能落在原位置的射线上，（射线为直斜8个方向，且不穿过其它棋子）
                    curGrids[pushFromRow][pushFromCol] = 2; //己方白棋落下的白棋的位置
                    curGrids[row][col] = 1; //挤走的对方黑棋的位置
                    isPushState = false; //落完就还原状态
                    addArrowSignal(pushFromRow, pushFromCol, row, col);
                    stepAdd();;
                    if (checkFormation(1)>0) { //此时可以判断黑棋是否被白方形成5连
                        doOver(WinMode.WHITE_WIN,player_white.getNickNameOrTemp() + "执白棋战胜" + player_black.getNickNameOrTemp());
                    }
                    else {
                        noticeBlackMove(); //再给黑棋走
                    }
                }
            }
            else { //常规落子状态
                if (curGrids[row][col] == 0) { //常规落在空格
                    curGrids[row][col] = 2;
                    addNewPutSignal(row, col);
                    stepAdd();;
                    if (checkFormation(2)>0) { //判断成5的为输啊
                        doOver(WinMode.BLACK_WIN,player_black.getNickNameOrTemp() + "执黑棋战胜" + player_white.getNickNameOrTemp());
                    }
                    else {
                        noticeBlackMove();
                    }
                }
                else if (curGrids[row][col] == 1) { //落在对方黑子上
                    if (isCantFall(row,col)) return;
                    curGrids[row][col] = 2; //黑棋位置被替换
                    stepAdd();;
                    if (checkFormation(2)>0) { //此时先判断输赢
                        doOver(WinMode.BLACK_WIN,player_black.getNickNameOrTemp() + "执黑棋战胜" + player_white.getNickNameOrTemp());
                    }
                    else { //白棋进入推棋状态
                        isPushState = true;
                        pushFromRow = row;
                        pushFromCol = col;
                        addWaitSignal(row, col, 2);
                        noticeWhiteMove();//通知还是白棋走
                    }
                }
            }
        }
    }

    //判断改位置是否被挡死了？挡死的棋子不能被对方落下
    private boolean isCantFall(int row, int col) {
        int[][] array = {{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1},};
        for (int[] a : array) {
            if (row + a[0] < 0 || row + a[0] >= curGrids.length || col + a[1] < 0 || col + a[1] >= curGrids[0].length){
                continue;
            }
            if (curGrids[row + a[0]][col + a[1]] == 0) {
                return false;
            }
        }
        return true;
    }

    //判断row和col所在的点是否在pushFromRow和pushFromCol的射线上（射线为直斜8个方向，且不穿过其它棋子）
    private boolean isOnTheRay(int pushFromRow, int pushFromCol, int row, int col) {
        if (curGrids[row][col] == 0) { //只能落在空位置上
            if (pushFromRow == row) {
                int addC = (col - pushFromCol) / Math.abs(col - pushFromCol); //因为前两个条件，这里的被除数不可能为0
                for (int a = pushFromCol + addC; a != col; a += addC) { //一旦两点之间有别的棋子，该位置就不能落子
                    if (curGrids[row][a] != 0) {
                        return false;
                    }
                }
                return true;
            }
            else if (pushFromCol == col) {
                int addR = (row - pushFromRow) / Math.abs(row - pushFromRow); //因为前两个条件，这里的被除数不可能为0
                for (int a = pushFromRow + addR; a != row; a += addR) { //一旦两点之间有别的棋子，该位置就不能落子
                    if (curGrids[a][col] != 0) {
                        return false;
                    }
                }
                return true;
            }
            else if (Math.abs(row - pushFromRow) == Math.abs(col - pushFromCol)) { //确保是在45°的斜线上
                int addC = (col - pushFromCol) / Math.abs(col - pushFromCol); //因为前两个条件，这里的被除数不可能为0
                int addR = (row - pushFromRow) / Math.abs(row - pushFromRow); //因为前两个条件，这里的被除数不可能为0
                for (int a = pushFromRow + addR, b = pushFromCol + addC; a != row; a += addR, b += addC) { //一旦两点之间有别的棋子，该位置就不能落子
                    if (curGrids[a][b] != 0) {
                        return false;
                    }
                }
                return true;
            }
            else {
                return false;
            }
        }
        else {
            return false;
        }
    }

    //获取成5的次数
    private int checkFormation(int value) {
        int rows = curGrids.length;
        int cols = curGrids[0].length;
        int formationCount = 0;

        // 水平方向
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols - 4; j++) {
                int length = 0;
                for (int k = j; k < j + 5; k++) {
                    if (curGrids[i][k] == value) {
                        length++;
                    }
                    else {
                        break;
                    }
                }
                if (length >= 5) {
                    formationCount += (length - 4);
                }
            }
        }

        // 垂直方向
        for (int i = 0; i < rows - 4; i++) {
            for (int j = 0; j < cols; j++) {
                int length = 0;
                for (int k = i; k < i + 5; k++) {
                    if (curGrids[k][j] == value) {
                        length++;
                    }
                    else {
                        break;
                    }
                }
                if (length >= 5) {
                    formationCount += (length - 4);
                }
            }
        }

        // 左上到右下方向
        for (int i = 0; i < rows - 4; i++) {
            for (int j = 0; j < cols - 4; j++) {
                int length = 0;
                for (int k = 0; k < 5; k++) {
                    if (curGrids[i + k][j + k] == value) {
                        length++;
                    }
                    else {
                        break;
                    }
                }
                if (length >= 5) {
                    formationCount += (length - 4);
                }
            }
        }

        // 右上到左下方向
        for (int i = 0; i < rows - 4; i++) {
            for (int j = 4; j < cols; j++) {
                int length = 0;
                for (int k = 0; k < 5; k++) {
                    if (curGrids[i + k][j - k] == value) {
                        length++;
                    }
                    else {
                        break;
                    }
                }
                if (length >= 5) {
                    formationCount += (length - 4);
                }
            }
        }

        return formationCount;
    }

}
